
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>
#include "global.h"



namespace LuaHelp {
	sol::table open_luaParameters(sol::this_state L) {
		sol::state_view lua(L);
		sol::table module=lua.script(R"(
		
require "lfs"
require "unity"
local nl = require "luaNumeric"
local debug = require"debug"
local math = require "math"


-----------------------------------------------------------------------------
--初始化参数
local Parameters={
	vals = {};
	str = '';
	idx = 0;
};
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--创建表和创建元表
function Parameters:new (o)
	o = o or {};
	self.__index = self;
	setmetatable(o,self)
	return o;
end
-----------------------------------------------------------------------------

function Parameters:get_index()
	self.idx = self.idx+1;
	--print(self.idx)
	return self.idx;
end

-----------------------------------------------------------------------------
--创建表和创建元表
function Parameters:print ()
	for k,v in pairs(self.vals) do
		print( k, v.expr, v.value, v.description, v.valid, v.msg )
	end
end
-----------------------------------------------------------------------------

function Parameters:add_variable (key,expr,desc,expr_impl)	
--function Parameters:add_variable (key,expr,desc)	
	assert( type(expr) == 'string', 'express is not a string! ' )
	assert( type(desc) == 'string', 'description is not a string! ' )
	-- assert( self.vals[key] == nil, " key exist yet! " )
	if self.vals[key] ~= nil then return false end;
	--print( "add var:", key, expr )

	self.vals[key]={ expr = expr;
				  valid = false;
				  description = desc;
				  expr_impl = expr;
				  idx = self:get_index(); 
				  };
	if expr_impl ~= nil and expr_iml ~= '' then 
		assert( type(expr_impl) == 'string', 'expr_impl is not a string! ' )
		self.vals[key].expr_impl = expr_impl;
	end
	self:parse_impl();
	self:update_sweep_value(key)

	self.need_init_sweep_list = true;
	return true;
end

function Parameters:change_variable_expression (key,expr)	
	assert( type(expr) == 'string', 'express is not a string! ' )
	if self.vals[key] == nil then return false end;
	self.vals[key].expr = expr;
	self.vals[key].expr_impl = expr;
	self:parse();
	self:update_sweep_value(key)
	
	self.need_init_sweep_list = true;

	return true;
end

function Parameters:change_variable_description (key,val)	
	assert( type(val) == 'string', 'description is not a string! ' )
	if self.vals[key] == nil then return false end;
	self.vals[key].description = val;
	--self:parse();
	self.need_init_sweep_list = true;
	return true;
end

function Parameters:swap_variables_index (key1,key2)	
	if self.vals[key1] == nil then return false end;
	if self.vals[key2] == nil then return false end;	
	idx1 = self.vals[key1].idx;
	idx2 = self.vals[key2].idx;
	self.vals[key1].idx = idx2;
	self.vals[key2].idx = idx1;
	self:parse();
	self:update_sweep_value(key)	
	self.need_init_sweep_list = true;
	return true;
end

-----------------------------------------------------------------------------
--解析扫描变量列表
function Parameters:update_sweep_value (key)
	if self.vals[key] == nil then return false end;
	if self.vals[key].sweep_state == true  then
		if type( self.vals[key].sweep_values_str ) ~= "string" then
			self.vals[key].sweep_values_str = tostring( self.vals[key].value );
		end
		self.vals[key].sweep_values = nl.new_vector( self.vals[key].sweep_values_str );
	else
		self.vals[key].sweep_values = nl.new_vector( tostring( self.vals[key].value ) );
	end
	self.need_init_sweep_list = true;
	return true;
end
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--解析所有扫描变量列表
function Parameters:update_sweep_values()	
	for k,v in pairs(self.vals) do
		--print(k,v)
		self:update_sweep_value(k)
	end
end
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--设置扫描参量的取值范围
function Parameters:change_variable_sweep_values (key,val)	
	assert( type(val) == 'string', 'sweep values is not a string! '..key..':'..val )
	if self.vals[key] == nil then return false end;
	self.vals[key].sweep_values_str = val;
	self:update_sweep_value(key);
	self.need_init_sweep_list = true;
	return true;
end
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--设置变量为扫描参量
function Parameters:change_variable_sweep_state (key,val)	
	assert( type(val) == 'string', 'sweep values is not a string! ' )
	if self.vals[key] == nil then return false end;
	if val=="true" then
		self.vals[key].sweep_state = true;
	else
		self.vals[key].sweep_state = false;
	end
	self:update_sweep_value(key);
	self.need_init_sweep_list = true;
	return true;
end
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--或者变量的扫描参量状态
function Parameters:get_variable_sweep_state (key)	
	assert( type(key) == 'string', 'sweep key is not a string! ' )
	if self.vals[key] == nil then return false end;
	if self.vals[key].sweep_state == nil then return false end;
	return self.vals[key].sweep_state;
end
-----------------------------------------------------------------------------


-----------------------------------------------------------------------------
--改变变量的名称
function Parameters:change_variable_name (key,newKey)	
	if self.vals[key] == nil then return false end;	
	if self:check_variable_name(newKey) == false then return false end;
	--print("change name:", key,newKey)
	local vold = self.vals[key];
	self.vals[key] = nil;
	self.vals[newKey] = vold;
	self:parse();
	self.need_init_sweep_list = true;
	return true;
end
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--检查变量名称
function Parameters:check_variable_name (key)	
	if self.vals[key] ~= nil then return false end;	
	local i,j = string.find(key, '[%a]+[%g]*')
	if i~=1 or j ~= #key then return false end;
	return true;
end
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--删除指定变量
function Parameters:remove_variable (key)	
	if self.vals[key] == nil then return false end;
	local removed = self.vals[key];
	self.vals[key] = nil;	
	self:parse();
	self.need_init_sweep_list = true;
	return true;
end
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--删除所有的变量
function Parameters:remove_all ()	
	for k,v in pairs(self.vals) do
		self.vals[k] = nil;	
	end
	self:parse();
	self.need_init_sweep_list = true;
	return true;
end
-----------------------------------------------------------------------------

function Parameters:parse_one_loop ()
	local r  = true;
	for k,v in pairs(self.vals) do
		local str = k .. ' = ' .. v.expr_impl .. '; \n';
		local f,msg = load(str);
		if f~= nil then debug.setupvalue(f,1,self.env); end
		local lr,lmsg = pcall(f)	
		self.vals[k].value = self.env[k];
		self.vals[k].valid = (self.vals[k].value~=nil);
		self.vals[k].msg = lmsg;
	end
	return r;
end

function Parameters:valid_paras ()	
	local n=0;
	for k,v in pairs( self.vals ) do
		if v.valid == true then
			n=n+1;
		end
	end
	return n;
end

function Parameters:num_paras ()	
	local n=0;
	for k,v in pairs( self.vals ) do
		n=n+1;
	end
	return n;
end

function Parameters:init_parser()	
	for k,v in pairs(self.vals) do
		self.vals[k].valid = false;
	end
	self.env = {};
	for k,v in pairs(math) do
	     self.env[k] =v;
	end
 	self.env['log10'] = nl.log10;
end

function Parameters:parse_impl()	
	local npre = 0;
	local n = 0;
	local nparas = self:num_paras();
	
	repeat
		npre = n;
		local sta = self:parse_one_loop();
		n = self:valid_paras();
	until( n==npre  or n==nparas)	
	
	self.valid = true;
	for k,v in pairs(self.vals) do
		if self.vals[k].valid == false then
			self.valid = false;
			break;
		end
	end

--	self.env_sweep = {};
--	for k,v in pairs(self.env) do
--	     self.env_sweep[k] =v;
--	end

end

-----------------------------------------------------------------------------
--解析所有变量
function Parameters:parse ()		
	self:init_parser();
	self:parse_impl();	
end
-----------------------------------------------------------------------------



-----------------------------------------------------------------------------
--初始化扫描变量列表
function Parameters:init_sweep_list()
	if self.need_init_sweep_list == false then return end;
	--print( "init sweep list" )
	self:update_sweep_values();
	self.sweeps_names = nl.new_svector();
	local list = nl.new_vvector();	
	
	local newTable ={}
	for k,v in pairs(self.vals)do
		v.key_name = k;
		table.insert(newTable,v)
	end
	table.sort( newTable, function(a,b) return a.idx<b.idx end )
	for k,v in pairs(newTable) do
		if v.sweep_state == true then
			if v.sweep_values:size()>0 then
				list:add( v.sweep_values );
				self.sweeps_names:add( tostring(v.key_name) );
			end
		end
	end
	self.sweep_values_list,self.sweep_idx = nl.grids(list);
	self.need_init_sweep_list = false;
end
-----------------------------------------------------------------------------


-----------------------------------------------------------------------------
--获取扫描变量列表
function Parameters:get_sweep_list(sweeps_names, values)

	self:init_sweep_list()

	sweeps_names:clear();
	for k,v in pairs( self.sweeps_names ) do 
		sweeps_names:add(v);
	end

	values:clear();
	values:reserve( #(self.sweep_values_list) );
	for k,v in pairs( self.sweep_values_list ) do 
		values:add(v);
	end
	return true;
end
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--获取扫描变量索引
function Parameters:get_sweep_index(idx)
	self:init_sweep_list()
	idx:clear();
	idx:reserve( #(self.sweep_idx) );
	for k,v in pairs( self.sweep_idx ) do 
		idx:add(v);
	end
	return true;
end
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--更新变量表
function Parameters:update_sweep_list_to_variables(idx)
	
	self:init_sweep_list()

	self:update_sweep_values();

	for k,v in pairs(self.vals) do
		self.vals[k].expr_impl = self.vals[k].expr;
	end

	if idx > #(self.sweep_values_list) then return false end;

	for k,v in pairs(self.sweeps_names) do
		self.vals[v].expr_impl = self.sweep_values_list[idx][k]
		--self.vals[v].expr = self.sweep_values_list[idx][k]
	end

	self:parse();

	return true;
end
-----------------------------------------------------------------------------



-----------------------------------------------------------------------------
--评估表达式
function Parameters:evaluate ( expr )	
	if not self.valid then return false,0.0 end
	local str = ' return ' .. expr .. '; \n';
	local f = load(str);
	if f== nil then return false,0.0 end
	debug.setupvalue(f,1,self.env);
	local lr,res = pcall(f)
	if lr == nil or type(res)~="number" then return false,0.0 end
	--assert(lr, res )
	return true,res;
end
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--评估表达式
function Parameters:evaluate_expr ( expr )	
	if not self.valid then return false,'' end	
	local res = expr;
	for k,v in pairs(self.vals) do
		 --print( k, v.expr, v.value, v.description, v.valid, v.msg )
		 res = string.gsub(res, '([%a_0-9]*)('..k..')([%a_0-9]*)', function (s1,s2,s3)
				-- print("s1:",type(s1),s1)
				-- print("s3:",type(s3),s3)

				if s1=='' and s3 == '' then
					--print(k,v.expr,v.value)
					return v.value
				end
				end)
		-- print(res);
	end
	return true,res;
	-- print(res);
end
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--[[评估表达式
function Parameters:envaluate ( expr )	
	if not self.valid then return false,0.0 end
	local str = ' return ' .. expr .. '; \n';
	local f = load(str);
	if f== nil then return false,0.0 end
	debug.setupvalue(f,1,self.env);
	local lr,res = pcall(f)
	if lr == nil or type(res)~="number" then return false,0.0 end
	--assert(lr, res )
	return true,res;
end
--]]---------------------------------------------------------------------------

-----------------------------------------------------------------------------
--检查表达式是否有语法错误
function Parameters:check_expression ( expr )	
	local str = ' return ' .. expr .. '; \n';
	local f, msg = load(str);
	return f~=nil;
end
-----------------------------------------------------------------------------



-----------------------------------------------------------------------------
--串行化
function Parameters:getList ()
	--self:print()
	local get_val=function( bsweep, value, svalue )
		 if bsweep and svalue then
				return svalue;
		 end
		 return value;
    end
	local list = {};
	for k,v in pairs(self.vals) do
		table.insert( list, { name=tostring(k), 
                              expr=v.expr, 
			      expr_impl = tostring(v.expr_impl),
                              value=tostring(self.env[k]),
							  description=tostring(v.description),
							  valid=tostring(v.valid),
 							  msg=tostring(v.msg),
							  values_str=tostring(v.sweep_values_str),
							  values=tostring(v.sweep_values),
							  sweep_state=tostring(v.sweep_state),
							  idx=v.idx } )
	end
	table.sort( list, function(a,b) return a.idx<b.idx end )

	return list;
end
-----------------------------------------------------------------------------

return Parameters;
		
		
		)");
		return module;
	}
}



extern "C" int luaopen_luaParameters(lua_State* L)
{
	return sol::stack::call_lua(L, 1, LuaHelp::open_luaParameters );
}

